package com.zx.security.reactive.handle;


import com.zx.core.wrapper.ResponseWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.bind.support.WebExchangeBindException;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;


/**
 * <p>
 * description: 全局异常处理<br>
 * create: 2024-08-23 13:48
 * </p>
 *
 * @author zhou  xun
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理WebExchangeBindException异常
     *
     * @param ex 异常信息
     * @return {@link Mono<ResponseWrapper>}
     * @author zhou  xun
     * @since 2025-05-14
     */
    @ExceptionHandler(WebExchangeBindException.class)
    public Mono<ResponseWrapper> handleWebExchangeBindException(WebExchangeBindException ex) {
        ResponseWrapper result = new ResponseWrapper();
        BindingResult bindingResult = ex.getBindingResult();
        List<ObjectError> globalErrors = bindingResult.getGlobalErrors();
        List<FieldError> fieldErrors = bindingResult.getFieldErrors();

        StringBuilder errorMessage = new StringBuilder();
        globalErrors.forEach(error -> {
            if (!errorMessage.isEmpty()) {
                errorMessage.append("; ");
            }
            errorMessage.append(error.getDefaultMessage());
        });
        fieldErrors.forEach(error -> {
            if (!errorMessage.isEmpty()) {
                errorMessage.append("; ");
            }
            errorMessage.append(error.getField()).append(": ").append(error.getDefaultMessage());
        });

        result.fail(errorMessage.toString());
        return Mono.just(result);
    }

    /**
     * 处理AccessDeniedException异常
     *
     * @param e        异常信息
     * @param exchange 交换
     * @return {@link Mono<ResponseWrapper>}
     * @author zhou  xun
     * @since 2025-05-14
     */
    @ExceptionHandler(AccessDeniedException.class)
    public Mono<ResponseWrapper> handleAccessDeniedException(AccessDeniedException e, ServerWebExchange exchange) {
        ResponseWrapper result = new ResponseWrapper();
        String requestPath = exchange.getRequest().getPath().toString();
        log.warn("请求地址'{}', 权限不足: {}", requestPath, e.getMessage());
        result.fail("权限不足");
        return Mono.just(result);
    }

    /**
     * 处理运行时异常
     *
     * @param e        异常信息
     * @param exchange 交换
     * @return {@link Mono<ResponseWrapper>}
     * @author zhou  xun
     * @since 2025-05-14
     */
    @ExceptionHandler(RuntimeException.class)
    public Mono<ResponseWrapper> handleRuntimeException(RuntimeException e, ServerWebExchange exchange) {
        ResponseWrapper result = new ResponseWrapper();
        logError(exchange, e);
        result.fail(e.getMessage());
        return Mono.just(result);
    }

    /**
     * 处理一般异常
     *
     * @param e        异常信息
     * @param exchange 交换
     * @return {@link Mono<ResponseWrapper>}
     * @author zhou  xun
     * @since 2025-05-14
     */
    @ExceptionHandler(Exception.class)
    public Mono<ResponseWrapper> handleException(Exception e, ServerWebExchange exchange) {
        ResponseWrapper result = new ResponseWrapper();
        logError(exchange, e);
        result.fail(e.getMessage());
        return Mono.just(result);
    }

    // 提取公共日志记录逻辑
    private void logError(ServerWebExchange exchange, Exception e) {
        String requestPath = exchange.getRequest().getPath().toString();
        log.error("请求地址'{}', 发生未知异常.", requestPath, e);
    }

}

